//
//  String+StrToArray.swift
//  Unibet
//
//  Created by HaoSheng on 2020/4/27.
//  Copyright © 2020 蜗牛. All rights reserved.
//

import Foundation
import Security
import CommonCrypto
import UIKit

public extension String {
    
    ///stirng转成单个字符的数组
    public var charactersArray: [Character] {
        return Array(self)
    }
    
    //根据range截取a[3,5] 从3开始截取5位
    public subscript(index:Int , length:Int)->String{

        guard index < count else {
            return ""
        }

        let startIndex = self.index(self.startIndex, offsetBy: index)
        let endIndex = self.index(startIndex, offsetBy: length)
        return String(self[startIndex..<endIndex])

    }
    
    /// 截取字符串的后n位
    func suffixSubstring(_ length: Int) -> String {
        // 如果长度小于0，返回空字符串
        guard length > 0 else { return "" }
        
        // 如果请求长度超过字符串长度，返回整个字符串
        if length >= self.count {
            return self
        }
        
        // 安全提取后n位字符
        let startIndex = self.index(self.endIndex, offsetBy: -length)
        return String(self[startIndex..<self.endIndex])
    }
    
    /// 根据下标获取某个下标字符
    public subscript(index index: Int) -> String {

        if index < 0 || index >= self.count{
            return ""
        }
        
        let someIndex = self.index(self.startIndex, offsetBy: index)
        return String(self[someIndex])
        
    }
    
    
    
    /// 根据约束宽度和字体计算高度
    func height(withWidth width: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(
            with: constraintRect,
            options: [.usesLineFragmentOrigin, .usesFontLeading],
            attributes: [.font: font],
            context: nil
        )
        return ceil(boundingBox.height) // 向上取整避免截断
    }

    /// 根据约束高度和字体计算宽度
    func width(withHeight height: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
        let boundingBox = self.boundingRect(
            with: constraintRect,
            options: [.usesLineFragmentOrigin, .usesFontLeading],
            attributes: [.font: font],
            context: nil
        )
        return ceil(boundingBox.width)
    }
    
    
    
    
    // MARK: - 手机号码
    /// 验证电话号码，正确返回 true
    public func checkPhoneNumber() -> Bool {
        // 长度验证 (兼容手机号和固话)
        guard [9, 10, 11, 12].contains(self.count) else {
            return false
        }
        
        // 正则表达式优化（使用原始字符串避免转义）
        let patterns = [
            // 通用手机号正则（兼容最新号段）
            #"^1([38]\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|9[0-35-9])\d{8}$"#,
            
            // 固话正则（支持3-4位区号）
            #"^(0\d{2,3}-?)?[1-9]\d{6,7}$"#,
            
            // 虚拟运营商/特殊号段（170/171/167等）
            #"^(1(70|71|67)\d{8}|95\d{8})$"#
        ]
        
        return patterns.contains { pattern in
            NSPredicate(format: "SELF MATCHES %@", pattern).evaluate(with: self)
        }
    }
    
    ///在电话字符串中加上横线
    public func phoneAddLine() -> String {
        
        let phone = self.prefix(3) + "-" + self[3,4]
        
        return phone  + "-" + self.suffix(4)
    }
    
    ///在电话字符串中加上空格
    public func phoneAddSpace() -> String {
        
        let phone = self.prefix(3) + " " + self[3,4]
        
        return phone  + " " + self.suffix(4)
    }
    
    
    
    
    
    // MARK: - 加密
    
    
    /* MD5 加密 */
    /**
     - returns: the String, as an MD5 hash.
     */
    public var md5: String {
        let str = self.cString(using: String.Encoding.utf8)
        let strLen = CUnsignedInt(self.lengthOfBytes(using: String.Encoding.utf8))
        let digestLen = Int(CC_MD5_DIGEST_LENGTH)
        let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
        CC_MD5(str!, strLen, result)
    
        let hash = NSMutableString()

        for i in 0..<digestLen {
            hash.appendFormat("%02x", result[i])
        }

        result.deallocate()
        return hash as String
    }
    
    /* SHA256 加密 */
    /**
     - returns: the String, as an SHA256 hash.
     */
    public var sha256: String {
        let utf8 = cString(using: .utf8)
        var digest = [UInt8](repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
        CC_SHA256(utf8, CC_LONG(utf8!.count - 1), &digest)
        return digest.reduce("") { $0 + String(format:"%02x", $1) }
    }
    
    /// 从 PKCS#8 数据末尾提取 32 字节
    public func parsePKCS8Ed25519Key() -> Data? {
        guard let pkcs8Data = Data(base64Encoded: self),
              pkcs8Data.count >= 48 else {
            return nil
        }
        return pkcs8Data.suffix(32)
    }
    
    /// 字符串转 rsa 私钥
    public func createPrivateKey() -> SecKey? {
        // 1. 去除 PEM 头尾
        let keyString = self
            .replacingOccurrences(of: "-----BEGIN PRIVATE KEY-----", with: "")
            .replacingOccurrences(of: "-----END PRIVATE KEY-----", with: "")
            .replacingOccurrences(of: "\r", with: "")
            .replacingOccurrences(of: "\n", with: "")
        
        // 2. Base64 解码
        guard let keyData = Data(base64Encoded: keyString) else {
            print("私钥 Base64 解码失败")
            return nil
        }
        
        // 3. 创建字典，指定密钥参数
        let options: [String: Any] = [
            kSecAttrKeyType as String:            kSecAttrKeyTypeRSA,
            kSecAttrKeyClass as String:           kSecAttrKeyClassPrivate,
//            kSecAttrKeySizeInBits as String:      1024,
//            kSecReturnPersistentRef as String:    true
        ]
        
        // 4. 创建 SecKey 对象
        var error: Unmanaged<CFError>?
        guard let secKey = SecKeyCreateWithData(keyData as CFData, options as CFDictionary, &error) else {
            if let err = error?.takeRetainedValue() {
                print("SecKey 创建失败：\(err.localizedDescription)")
            }
            return nil
        }
        
        return secKey
    }
    
    /// rsa 解密 privateKey私钥
    public func rsaDecrypt(privateKey: SecKey) -> String? {
        guard let cipherData = Data(base64Encoded: self) else {
            print("密文 Base64 解码失败")
            return nil
        }
        
        var error: Unmanaged<CFError>?
        
        // 使用 SecKey API 进行解密
        guard let decryptedData = SecKeyCreateDecryptedData(privateKey,
                                                            SecKeyAlgorithm.rsaEncryptionPKCS1,
                                                            cipherData as CFData,
                                                            &error) as Data? else {
            print("解密失败: \(error!.takeRetainedValue() as Error)")
            return nil
        }
        
        // 解密后的数据转字符串
        let decryptedString = String(data: decryptedData, encoding: .utf8)
        return decryptedString
    }
    
    
    // MARK: - 字符串转类
    
    ///字符传转类
    public func toClass() -> AnyClass?{
        //1、获swift中的命名空间名
        var name = Bundle.main.object(forInfoDictionaryKey: "CFBundleExecutable") as? String
        //2、如果包名中有'-'横线这样的字符，在拿到包名后，还需要把包名的'-'转换成'_'下横线
        name = name?.replacingOccurrences(of: "-", with: "_")
        //3、拼接命名空间和类名，”包名.类名“
        let fullClassName = name! + "." + self
        guard let cls = NSClassFromString(fullClassName)  else{
            print("未找到 " + self + " 类，转换失败！")
            return nil
        }
        // 在这里已经可以return了   返回类型:AnyClass!
        return cls;
    }


    ///VC字符串转类实例
    @MainActor public func toViewController() -> UIViewController?{
        
        //通过NSClassFromString获取到最终的类，由于NSClassFromString返回的是AnyClass，这里要转换成UIViewController.Type类型
        guard let classType = self.toClass() as? UIViewController.Type  else{
            return nil
        }
        return classType.init()
    }

    
    /// 使用指定格式和可选时区、locale，从字符串创建 Date 实例
    /// - Parameters:
    ///   - format: 日期格式，如 yyyy-MM-dd HH:mm:ss
    ///   - timeZone: 时区，默认当前时区
    ///   - locale: 区域设置，默认 en_US_POSIX，保证解析稳定
    /// - Returns: 转换成功的 Date，失败返回 nil
    public func toDate(format: String = "yyyy-MM-dd HH:mm:ss",
                       timeZone: TimeZone = .current,
                       locale: Locale = Locale(identifier: "en_US_POSIX")) -> Date? {
        let formatter = DateFormatter()
        formatter.dateFormat = format
        formatter.timeZone = timeZone
        formatter.locale = locale
        return formatter.date(from: self)
    }
    
    /// 空字符串返回默认值
    public func defaultString(_ defaultValue: String) -> String {
        if self.isEmpty {
            return defaultValue
        }
        return self
    }
    
    /// 去除空格
    func removeSpaces() ->String{
        return replacingOccurrences(of: " ", with: "")
    }
    
    /// 去除中文和中文符号
    mutating func removeChineseCharacters() {
        var string = self
        // 正则匹配所有中文字符和中文符号
        let pattern = "[\\u4e00-\\u9fff\\u3000-\\u303f\\uff00-\\uffef]+"
        if let regex = try? NSRegularExpression(pattern: pattern, options: []) {
            let range = NSRange(location: 0, length: string.utf16.count)
            // 替换匹配到的中文字符为空字符串
            string = regex.stringByReplacingMatches(in: string, options: [], range: range, withTemplate: "")
        }
        self = string
    }
    
    /// 在2个拼接字符之间加上 +
    public static func joinStrings(_ str1: String?, _ str2: String?) -> String {
        let s1 = str1 ?? ""
        let s2 = str2 ?? ""

        if !s1.isEmpty && !s2.isEmpty {
            return s1 + "+" + s2
        } else {
            return s1 + s2
        }
    }
    
    /// 判断字符串是否全部是中文字符包括空格
    public func isAllChinese() -> Bool {
        // 正则表达式：从头到尾全部是中文字符
        // \u4E00-\u9FFF 是常用汉字范围
        let trimmed = self.replacingOccurrences(of: "\\s", with: "", options: .regularExpression)
        let pattern = "^[\\u4E00-\\u9FFF]+$"
        let regex = try! NSRegularExpression(pattern: pattern)
        let range = NSRange(location: 0, length: trimmed.utf16.count)
        let match = regex.firstMatch(in: trimmed, options: [], range: range)
        return match != nil
    }
    
    /// 判断字符串是否只包含中文字符、符号和空格（不包含字母和数字）
    public func isChineseWithSymbols() -> Bool {
        // 允许中文字符（\u4E00-\u9FFF）、中文标点符号（\u3000-\u303F）、全角符号（\uFF00-\uFFEF）、空格（\u0020）
        // 你可以根据需要调整符号范围
        let pattern = "^[\\u4E00-\\u9FFF\\u3000-\\u303F\\uFF00-\\uFFEF\\s]+$"
        
        let regex = try! NSRegularExpression(pattern: pattern)
        let range = NSRange(location: 0, length: self.utf16.count)
        let match = regex.firstMatch(in: self, options: [], range: range)
        
        return match != nil
    }
    
    
    /// 将 JSON 字符串格式化为带缩进的 JSON 字符串
    public func formattedJSONString() -> String {
        guard let data = self.data(using: .utf8) else {
            return self
        }
        do {
            let jsonObject = try JSONSerialization.jsonObject(with: data, options: [])
            let prettyData = try JSONSerialization.data(withJSONObject: jsonObject, options: [.prettyPrinted])
            if let prettyString = String(data: prettyData, encoding: .utf8) {
                return prettyString
            } else {
                return self
            }
        } catch {
            return self
        }
    }
    
}




public extension Optional where Wrapped == String {
    
    /// 为空或空字符串返回默认值
    public func defaultString(_ defaultValue: String) -> String {
        self.flatMap { $0.isEmpty ? nil : $0 } ?? defaultValue
    }
    
    /// 判断可选字符串是否为空（nil 或空字符串）为空true
    var isEmptyOrNil: Bool {
        return self?.isEmpty ?? true
    }
    
}



public extension Array where Element == String {
    
//    /// 更新元素
//    public mutating func update(str:String){
//        
//        var arr = self
//        arr.removeAll { sstr in
//            str == sstr
//        }
//        
//        arr.append(str)
//        
//        self = arr
//    }
//    
//    /// 存在元素删除，不存在添加
//    public mutating func toggleElement(_ element: Element) {
//        if let index = firstIndex(of: element) {
//            remove(at: index) // 存在则删除
//        } else {
//            append(element) // 不存在则添加
//        }
//    }
//    
}



// MARK: - 字符串相似度计算工具
public enum StringSimilarity {
    
    /// 交并集相似度计算
    public static func jaccardSimilarity<T: Hashable>(_ arr1: [T], _ arr2: [T]) -> Double {
        let set1 = Set(arr1)
        let set2 = Set(arr2)
        
        let intersectionCount = set1.intersection(set2).count
        let unionCount = set1.union(set2).count
        
        guard unionCount > 0 else { return 1.0 }
        return Double(intersectionCount) / Double(unionCount)
    }
    
    /// 改进的相似度计算，适用于OCR识别结果
    public static func improvedSimilarity(_ arr1: [String], _ arr2: [String]) -> Double {
        let combined1 = preprocessArray(arr1)
        let combined2 = preprocessArray(arr2)
        
        if combined1 == combined2 {
            return 1.0
        }
        
        let lcsLength = longestCommonSubsequence(combined1, combined2)
        let maxLength = max(combined1.count, combined2.count)
        
        guard maxLength > 0 else { return 1.0 }
        return Double(lcsLength) / Double(maxLength)
    }
    
    /// 基于编辑距离的相似度计算
    public static func levenshteinSimilarity(_ arr1: [String], _ arr2: [String]) -> Double {
        let combined1 = preprocessArray(arr1)
        let combined2 = preprocessArray(arr2)
        
        let distance = levenshteinDistance(combined1, combined2)
        let maxLength = max(combined1.count, combined2.count)
        
        guard maxLength > 0 else { return 1.0 }
        return 1.0 - Double(distance) / Double(maxLength)
    }
    
    /// 组合相似度（取两者中较高的）
    public static func combinedSimilarity(_ arr1: [String], _ arr2: [String]) -> Double {
        let lcsSim = improvedSimilarity(arr1, arr2)
        let levSim = levenshteinSimilarity(arr1, arr2)
        return max(lcsSim, levSim)
    }
    
    // MARK: - 私有辅助方法
    
    /// 预处理字符串数组，去除标点和符号
    private static func preprocessArray(_ arr: [String]) -> String {
        let joined = arr.joined(separator: " ").lowercased()
        let filtered = joined.filter { $0.isLetter || $0.isNumber }
        return filtered
    }

    
    /// 计算最长公共子序列长度
    private static func longestCommonSubsequence(_ s1: String, _ s2: String) -> Int {
        let n = s1.count, m = s2.count
        var dp = Array(repeating: Array(repeating: 0, count: m + 1), count: n + 1)
        
        let arr1 = Array(s1)
        let arr2 = Array(s2)
        
        for i in 1...n {
            for j in 1...m {
                if arr1[i - 1] == arr2[j - 1] {
                    dp[i][j] = dp[i - 1][j - 1] + 1
                } else {
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
                }
            }
        }
        
        return dp[n][m]
    }
    
    /// 计算编辑距离
    private static func levenshteinDistance(_ s1: String, _ s2: String) -> Int {
        let s1Array = Array(s1)
        let s2Array = Array(s2)
        let n = s1Array.count
        let m = s2Array.count
        
        if n == 0 { return m }
        if m == 0 { return n }
        
        var dp = Array(repeating: Array(repeating: 0, count: m + 1), count: n + 1)
        
        for i in 0...n { dp[i][0] = i }
        for j in 0...m { dp[0][j] = j }
        
        for i in 1...n {
            for j in 1...m {
                if s1Array[i - 1] == s2Array[j - 1] {
                    dp[i][j] = dp[i - 1][j - 1]
                } else {
                    dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
                }
            }
        }
        
        return dp[n][m]
    }
}
